import './playing_card.dart';
enum CardsType {
  illegal,
  single,
  twain,
  connector,
  three,
  threeSingle,
  threeTwain,
  fourTwoSingle,
  fourTwoTwain,
  four,
  wangFried,
  pairs,
  triplets,
  tripletsSingle,
  tripletsTwain
}
class HandCards {
  List<String> cardsText;

  Map<String, List<CardSuit>> cardsMap;
  List<String> sortedCardsNum;
  CardsType cardsType;
  Map<String, List> cardFormat = {'main':[], 'sub': []};//cardTyp:0:main;1:sub//三带..;四带..;飞机;

  static const Map<String, int> CARDSNUM = {'3':0,'4':1,'5':2,'6':3,'7':4,'8':5,'9':6,'10':7,'J':8,'Q':9,'K':10,'A':11,'2':12,'W':13};

  HandCards({this.cardsText}) {
    this.cardsMap = toMap();
    sortedCardsNum = this.cardsMap.keys.toList();
    sortedCardsNum.sort((card1, card2){
      return CARDSNUM[card1] - CARDSNUM[card2];
    });
    this.cardsType = getCardsType();
    this.formatCards();
  }

  int get cardsCount => this.cardsText.length;

  Map<String, List<CardSuit>> toMap() {
    Map<String, List<CardSuit>> _cards = {};
    CardSuit _cardSuit;
    String _cardNum;
    this.cardsText.forEach((cardText){
      _cardSuit = CardSuit.values[int.parse(cardText.substring(cardText.length-1))];
      _cardNum = cardText.substring(0, cardText.length-1);
      if(null != _cards[_cardNum]) {
        _cards[_cardNum].add(_cardSuit);
      }else {
        _cards[_cardNum] = [_cardSuit];
      }
    });
    return _cards;
  }
  
  void formatCards() {
    if(this.cardsType == CardsType.threeSingle || this.cardsType == CardsType.threeTwain) {
      this.sortedCardsNum.forEach((cardNum){
        if(this.cardsMap[cardNum].length == 3) {
          this.cardFormat['main'].add(cardNum);
        }else {
          this.cardFormat['sub'].add(cardNum);
        }
      });
    }else if(this.cardsType == CardsType.fourTwoSingle || this.cardsType == CardsType.fourTwoTwain) {
      this.sortedCardsNum.forEach((cardNum){
        if(this.cardsMap[cardNum].length == 4) {
          this.cardFormat['main'].add(cardNum);
        }else {
          this.cardFormat['sub'].add(cardNum);
        }
      });
    }else if(this.cardsType == CardsType.triplets || this.cardsType == CardsType.tripletsSingle || this.cardsType == CardsType.tripletsTwain) {
      this.sortedCardsNum.forEach((cardNum){
        if(this.cardsMap[cardNum].length == 3) {
          this.cardFormat['main'].add(cardNum);
        }if(this.cardsMap[cardNum].length == 4) {
          this.cardFormat['main'].add(cardNum);
          this.cardFormat['sub'].add(cardNum);
        }else {
          this.cardFormat['sub'].add(cardNum);
        }
      });
    }else {
      this.cardFormat['main'] = this.sortedCardsNum;
    }
  }
  CardsType getCardsType() {
    if(this.cardsCount == 1) return CardsType.single;
    if(this.cardsText.length == 2 && this.sortedCardsNum.length == 1 && this.sortedCardsNum[0] == 'W') {
      return CardsType.wangFried;
    }
    if(isSameSuit()) {
      return this.cardsCount == 2 ? this.sortedCardsNum[0]=='W' ? CardsType.wangFried:CardsType.twain : this.cardsCount == 3 ? CardsType.three : this.cardsCount == 4 ? CardsType.four : CardsType.illegal;
    }
    if(this.cardsCount < 4) return CardsType.illegal;
    int firstCardSuitCount = this.cardsMap[this.sortedCardsNum[0]].length;
    if(this.cardsCount == 4) {
      return this.sortedCardsNum.length == 2 && (firstCardSuitCount == 1 || firstCardSuitCount == 3) ? CardsType.threeSingle : CardsType.illegal;
    }
    if(this.cardsCount == 5) {
      if(this.sortedCardsNum.length == 2 && (firstCardSuitCount == 2 || firstCardSuitCount == 3)) {
        return CardsType.threeTwain;
      }
    }
    if(isSpecialIllegal()) return CardsType.illegal;
    if(isPairs()) {
      return CardsType.pairs;
    }
    int resIsTriplets = isTriplets();
    if(resIsTriplets != 0) {
      return resIsTriplets == 1 ? CardsType.tripletsSingle : resIsTriplets == 2 ? CardsType.tripletsTwain : CardsType.triplets;
    }
    if(this.cardsCount == 6) {
      if(this.sortedCardsNum.length == 3) {
        int secCardSuitCount = this.cardsMap[this.sortedCardsNum[1]].length;
        if((firstCardSuitCount == 4 || firstCardSuitCount == 1) && (secCardSuitCount == 4 || secCardSuitCount == 1)) {
          return CardsType.fourTwoSingle;
        }
      }
      if(this.sortedCardsNum.length == 2 && (firstCardSuitCount == 4 || firstCardSuitCount == 2)) {
        return CardsType.fourTwoSingle;
      }
    }
    if(this.cardsCount == 8 && this.sortedCardsNum.length == 3) {
      int secCardSuitCount = this.cardsMap[this.sortedCardsNum[1]].length;
      if((firstCardSuitCount == 4 && secCardSuitCount == 2) || (firstCardSuitCount == 2 && secCardSuitCount == 4) || (firstCardSuitCount == 2 && secCardSuitCount == 2)) {
        return CardsType.fourTwoTwain;
      }
    }
    return isConnector() ? CardsType.connector : CardsType.illegal;
  }
  //特殊的非法出牌
  bool isSpecialIllegal() {
    //多个四个
    if(this.cardsCount >= 8 && this.cardsMap.values.every((cardSuits){return cardSuits.length == 4;})) {
      return true;
    }
    return false;
  }
  //对子;三个;四个
  bool isSameSuit() {
    return this.sortedCardsNum.length == 1;
  }
  //是否连续
  bool isCardsConnect(List<String> cards) {
    for(int index = 0; index < cards.length - 1; index ++) {
      if(CARDSNUM[cards[index]] + 1 != CARDSNUM[cards[index+1]]) {
        return false;
      }
    }
    return true;
  }
  //连牌
  bool isConnector() {
    if(this.cardsCount >= 5 && this.cardsCount == this.sortedCardsNum.length && !has2OrW()) {
      return isCardsConnect(this.sortedCardsNum);
    }else {
      return false;
    }
  }
  //连对
  bool isPairs() {
    if(this.cardsCount >= 6 && this.sortedCardsNum.length > 2 && !has2OrW()) {
      return this.cardsMap.values.every((cardSuits){
        return cardSuits.length == 2;
      }) && isCardsConnect(this.sortedCardsNum) ? true : false;
    }else {
      return false;
    }
  }
  //飞机
  int isTriplets() {  //0:不是;1:飞机带单;2:飞机带双;3:不带
    if(this.cardsCount >= 6) {
      int res;
      int withType;  //带牌类型:1or2
      int withCardsCount = 0; //带的牌数
      int cardSuitsCount;
      List<String> threeCards = []; //三个的牌
      this.sortedCardsNum.forEach((cardNum){
        cardSuitsCount = this.cardsMap[cardNum].length;
        if(cardSuitsCount == 3) {
          threeCards.add(cardNum);
        }else {
          if(cardSuitsCount == 4) {
            threeCards.add(cardNum);
            cardSuitsCount = 1;
          }
          if(cardSuitsCount == 1 || cardSuitsCount == 2){
            if(withType == null) {
              withType = cardSuitsCount;
            }else if(withType == 2 && cardSuitsCount == 1) {
              withType = 1;
              withCardsCount *= 2;
            }else if(withType == 1 && cardSuitsCount == 2){
              withCardsCount ++;
            }
            withCardsCount ++;
          }else {
            res = 0;
          }
        }
      });
      if(null != res) {
        return res;
      }
      //是否连续
      if(!isCardsConnect(threeCards)) return 0;
      
      return withCardsCount == 0 ? 3 : threeCards.length == withCardsCount ? withType : 0;
    }else {
      return 0;
    }
  }
  //是否含2和w//用于判断连牌和连对
  bool has2OrW() {
    return this.cardsMap.containsKey('2')||this.cardsMap.containsKey('W');
  }
  
  int compareTo(HandCards compareCards) {
    CardsType compareCardsType = compareCards.cardsType;
    CardsType thisCardsType = this.cardsType;
    if(compareCardsType == CardsType.illegal || thisCardsType == CardsType.wangFried || (thisCardsType == CardsType.four && compareCardsType != CardsType.four && compareCardsType!= CardsType.wangFried)) {
      return 1;
    }
    if(thisCardsType == CardsType.illegal || compareCardsType == CardsType.wangFried || (compareCardsType == CardsType.four && thisCardsType != CardsType.four && thisCardsType!= CardsType.wangFried)){
      return -1;
    }
    
    if(compareCards.cardsText.length == this.cardsText.length && compareCardsType == thisCardsType) {
      int dis = CARDSNUM[this.cardFormat['main'][0]] - CARDSNUM[compareCards.cardFormat['main'][0]];
      if(dis == 0 && this.cardFormat['main'][0] == 'W') {
        dis = this.cardsMap['W'][0].index - compareCards.cardsMap['W'][0].index;
      }
      return dis > 0 ? 1 : dis < 0 ? -1 : 0;
    }else {
      return -1;
    }
  }
  List<String> toRightList() {
    List<String> res = [];
    if(cardsType == CardsType.tripletsSingle) { //飞机中存在炸弹牌
      this.cardFormat['main'].forEach((cardNum){
        List<CardSuit> cardSuits = this.cardsMap[cardNum];
        for(int index = 0; index < 3 && index < cardSuits.length; index ++) {
          res.add(cardNum + cardSuits[index].index.toString());
        }
      });
      this.cardFormat['sub'].forEach((cardNum){
        List<CardSuit> subCardSuits = this.cardsMap[cardNum];
        if(subCardSuits.length == 4) {
          res.add(cardNum + subCardSuits[3].index.toString());
        }else {
          subCardSuits.forEach((cardSuit){
            res.add(cardNum + cardSuit.index.toString());
          });
        }
      });
    }else {
      this.cardFormat['main'].forEach((cardNum){
        this.cardsMap[cardNum].forEach((cardSuit){
          res.add(cardNum + cardSuit.index.toString());
        });
      });
      this.cardFormat['sub'].forEach((cardNum){
        this.cardsMap[cardNum].forEach((cardSuit){
          res.add(cardNum + cardSuit.index.toString());
        });
      });
    }
    return res;
  }
}